Integração R e Python

um caso de amor (e ódio)

Rafael Lira

Tech Stack

Estrutura da apresentação

  • Motivação

  • Introdução à linguagem python

  • Integração R/python

  • Equivalências do da disciplina no python

  • ML com scikit-learn no R

R ou Python?

Uma briga (quase) superada …

Uma briga (quase) superada …

Qual vocês acham que é o R?

Uma briga (quase) superada …

Fonte: DataCamp

Hadley Wichman

Cientista chefe na RStudio (futura Posit)

Não é uma batalha […] use o que te faz feliz!” , 2019

Diferenças, vantagens, desvantagens….

R

  • Usuários: Acadêmicos, estatísticos, biólogos, economistas …

  • Modelos em poucas linhas, possibilidade de escrever de várias formas.

  • Estatística e visualização (ggplot2!)

  • CRAN, GitHub: + pacotes, + fáceis de instalar e mais documentados.

Python

  • Usuários: Cient. computação, Eng. software …

  • Sensível a indentação.

  • ETL/ML workflows e ambientes de produção escaláveis

  • Pacotes/dependências mais “chatinhos”

E porque integrar R/python afinal?

Argumento 1: Uma pode ser melhor que a outra para um determinado problema.

Python melhor:

  • 2012: todos os requisitos.

R veio depois com:

  • Resumindo: O foco é resolver o problema. Leia o post.

E porque integrar R/python afinal?

  • Argumento 1: Uma pode ser melhor que a outra para um determinado problema.

    R melhor:

    RStudio recentemente:

    Shiny for Python

E porque integrar R/python afinal?

Argumento 2: A sua equipe pode ter pessoas de diferentes linguagens.

(ou uma mistura dos dois!)

Exemplos

1) A preparação dessa apresentação

2) Esta apresentação no rstudio::conf(2022)

Diversidade de pensamento

Mais chances de encontrar a melhor solução para um problema de forma mais eficiente. Leia

Basicamente …

Python no R

Reticulate:

O pacote da trégua

Scripts do Python no R

  • Execução de scripts do Python interagindo com a sessão do R;
  • Tradução entre objetos do R e do Python (como entre data frames do R e do Pandas);

Reticulate

Lista de comandos

ls("package:reticulate")
 [1] "%as%"                               "array_reshape"                     
 [3] "as_iterator"                        "conda_binary"                      
 [5] "conda_create"                       "conda_install"                     
 [7] "conda_list"                         "conda_python"                      
 [9] "conda_remove"                       "conda_version"                     
[11] "configure_environment"              "dict"                              
[13] "eng_python"                         "import"                            
[15] "import_builtins"                    "import_from_path"                  
[17] "import_main"                        "install_miniconda"                 
[19] "install_python"                     "iter_next"                         
[21] "iterate"                            "miniconda_path"                    
[23] "miniconda_update"                   "np_array"                          
[25] "py"                                 "py_available"                      
[27] "py_call"                            "py_capture_output"                 
[29] "py_clear_last_error"                "py_config"                         
[31] "py_config_error_message"            "py_del_attr"                       
[33] "py_del_item"                        "py_dict"                           
[35] "py_discover_config"                 "py_ellipsis"                       
[37] "py_eval"                            "py_exe"                            
[39] "py_func"                            "py_function_docs"                  
[41] "py_function_wrapper"                "py_get_attr"                       
[43] "py_get_item"                        "py_has_attr"                       
[45] "py_help"                            "py_help_handler"                   
[47] "py_id"                              "py_install"                        
[49] "py_is_null_xptr"                    "py_iterator"                       
[51] "py_last_error"                      "py_len"                            
[53] "py_list_attributes"                 "py_load_object"                    
[55] "py_main_thread_func"                "py_module_available"               
[57] "py_none"                            "py_numpy_available"                
[59] "py_run_file"                        "py_run_string"                     
[61] "py_save_object"                     "py_set_attr"                       
[63] "py_set_item"                        "py_set_seed"                       
[65] "py_str"                             "py_suppress_warnings"              
[67] "py_to_r"                            "py_to_r_wrapper"                   
[69] "py_unicode"                         "py_validate_xptr"                  
[71] "py_version"                         "py_versions_windows"               
[73] "PyClass"                            "r_to_py"                           
[75] "register_class_filter"              "register_help_topics"              
[77] "register_module_help_handler"       "register_suppress_warnings_handler"
[79] "repl_python"                        "source_python"                     
[81] "tuple"                              "use_condaenv"                      
[83] "use_miniconda"                      "use_python"                        
[85] "use_python_version"                 "use_virtualenv"                    
[87] "virtualenv_create"                  "virtualenv_exists"                 
[89] "virtualenv_install"                 "virtualenv_list"                   
[91] "virtualenv_python"                  "virtualenv_remove"                 
[93] "virtualenv_root"                   

Reticulate:

use_virtualenv("./venv", required = TRUE)
# py_install("pandas")
# py_install("numpy")
pd <- import("pandas", as = "pd", convert = FALSE)

repl_python(
  input = "import numpy as np
  array = np.array([[1,2],[3,4],[5.0,6]])
  print(array)
  print(type(array))"
)
>>>  import numpy as np
>>>    array = np.array([[1,2],[3,4],[5.0,6]])
>>>    print(array)
>>>    print(type(array))
array <- py$array
class(array)
[1] "matrix" "array" 
repl_python(
  input = "
  dictionary = {'alpha': 1, 'beta': 2, 'lista': list(range(5))}
  print(dictionary)
  print(type(dictionary))"
)
>>>  
>>>    dictionary = {'alpha': 1, 'beta': 2, 'lista': list(range(5))}
>>>    print(dictionary)
>>>    print(type(dictionary))
# Convertendo dicionário do Python para lista do R
(dictionary <- py$dictionary)
$alpha
[1] 1

$beta
[1] 2

$lista
[1] 0 1 2 3 4
class(dictionary)
[1] "list"

Rpy2:

Códigos do R no Python

Rcpp:

C++ no R

  • C++: Linguagem de médio/alto nível e com alta performance
  • Veloz
  • Eficiente

Pitfalls

Falta de suporte oficial para R

Suporte oficial do Heroku

Conversando com APIs

Falta de escalabilidade

  • Quando o gasto de tempo não vale a pena (curva de aprendizado)

Limitações do sistema

  • Falta de espaço em disco

  • Falta de RAM

  • Falta de Suporte

Scikit-learn

  • Popular biblioteca de machine learning para Python;

  • Vasto conjunto de algoritmos para processamento de dados e construção de modelos;

  • Consistente, eficiente e de fácil utilização;

  • Excelente documentação, repleta de exemplos e tutoriais.

Ferramentas do scikit-learn

Pré-processamento

  • Seleção, transformação, criação de variáveis;

  • Codificação de dados categorizados nominais e ordinais;

  • Redução de dimensionalidade (PCA, FA etc.);

  • Imputação de dados faltantes;

  • Manipulação de dados em texto.

  • etc.

Modelos

  • Regressão: linear, ridge, LASSO, SVR etc;
  • Classificação: regressão logística, árvore de decisão, SVM, naive Bayes, LDA/QDA etc;
  • Clusterização: K-Means, misturas gaussianas etc;
  • Outros:
    • Estimação de densidades de probabilidade;

    • Decomposição de sinais;

    • Detecção de anomalias;

    • Redes neurais.

Avaliação e seleção de modelos

  • Particionamento dos dados em treino-teste;

  • Métricas gerais de performance;

  • Estimação de hiperparâmetros;

  • Validação cruzada.

Integrando o scikit-learn ao R

Preparação

  • O primeiro passo é carregar o pacote reticulate e indicar onde serão executados os códigos Python; nesse caso, no ambiente virtual “venv”.
library(reticulate)
use_virtualenv("./venv", required = TRUE)
  • Caso precise criar esse ambiente virtual, primeiro execute:
use_python("C:/Users/user/anaconda3")
virtualenv_create("venv",
                  packages=c("scikit-learn"))

Exemplo: classificação de tumores

O data frame carregado dentro no R é passado para o ambiente Python como um data frame pandas.

library(readr)
breast_cancer = read_csv("./capitulos/scikit-learn/breast_cancer.csv")
  • No Python, esse data frame fica contido no objeto r.
import pandas as pd
print(r.breast_cancer)
     mean radius  mean texture  ...  worst fractal dimension    y
0          17.99         10.38  ...                  0.11890  0.0
1          20.57         17.77  ...                  0.08902  0.0
2          19.69         21.25  ...                  0.08758  0.0
3          11.42         20.38  ...                  0.17300  0.0
4          20.29         14.34  ...                  0.07678  0.0
..           ...           ...  ...                      ...  ...
564        21.56         22.39  ...                  0.07115  0.0
565        20.13         28.25  ...                  0.06637  0.0
566        16.60         28.08  ...                  0.07820  0.0
567        20.60         29.33  ...                  0.12400  0.0
568         7.76         24.54  ...                  0.07039  1.0

[569 rows x 31 columns]

No scikit-learn, para ajustar um modelo é preciso separar as colunas de covariáveis, representadas pela matriz X, da variável resposta y.

X = r.breast_cancer.drop("y", axis=1)
y = r.breast_cancer["y"] # 0 = maligno, 1 = benigno

Divisão em treino e teste

No contexto de machine learning, é rotineiro separar uma parte dos dados para testar a capacidade de um modelo, geralmente, 20% das observações. Isso pode ser feito do seguinte modo no sklearn:

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(
  X, y, test_size=0.20, random_state=42)

O parâmetro random_state fixa a semente de geração de números aleatórios para a reprodução de resultados.

O modelo

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.svm import LinearSVC

model = Pipeline([
  ("scaler", StandardScaler()),          # Padronização
  ("pca", PCA(n_components=5)),          # Componentes principais
  ("svc", LinearSVC(C=8.71, dual=False)) # Support Vector Machine
])
  • O pipeline é análogo ao pipe %>% do R:

    • Sequência de transformações, seguida de um modelo;

    • Unifica e simplifica as etapas de pré-processamento, estimação e ajuste de hiperparâmetros, e previsões.

  • Os hiperparâmetros n_components e C definidos podem ser ajustados utilizando métodos de validação cruzada (Grid Search, Random Search etc.) sobre o pipeline.

  • Com os hiperparâmetros definidos, ajusta-se o modelo aos dados de treino.
model.fit(X_train, y_train);
  • (Vazamento de dados). O pipeline ajuda a reforçar o uso de apenas os dados de treino para o ajuste.

  • Agora, a verificação da qualidade das previsões por meio da acurácia no conjunto de teste.
from sklearn.metrics import accuracy_score

y_pred = model.predict(X_test)
print("Precisão:", accuracy_score(y_test, y_pred))
Precisão: 0.9824561403508771

Exportando os resultados para o R

Podemos enfim armazenar alguma parte de interesse do resultado para trazer para o R, por exemplo, as previsões do modelo.

y_pred = model.predict(X)
  • De volta ao R, o objeto y_pred pode ser acessado através da lista py.
library(ggplot2)
breast_cancer$y_pred <- py$y_pred
qplot(x=y_pred, y=y, data=breast_cancer, geom="jitter")

library(ggplot2)
breast_cancer$y_pred <- py$y_pred
qplot(x=y_pred, y=y, data=breast_cancer, geom="jitter")

Materiais

  1. Para mais informações sobre a biblioteca scikit-learn, veja sua página na web e o guia de usuário;

  2. Como Usar Pipelines no Scikit-Learn - João Paulo Nogueira;

  3. Cross Validation - scikit-learn;

  4. GÉRON, Aurélien (2019). Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow;

  5. Translating between tidymodels and scikit-learn - Kelly Bodwin.